home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / misc / messages.c < prev    next >
C/C++ Source or Header  |  2003-04-07  |  17KB  |  498 lines

  1. /*****************************************************************************
  2.  * messages.c: messages interface
  3.  * This library provides an interface to the message queue to be used by other
  4.  * modules, especially intf modules. See config.h for output configuration.
  5.  *****************************************************************************
  6.  * Copyright (C) 1998-2002 VideoLAN
  7.  * $Id: messages.c,v 1.29 2003/01/15 13:46:05 massiot Exp $
  8.  *
  9.  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  10.  *          Samuel Hocevar <sam@zoy.org>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26.  
  27. /*****************************************************************************
  28.  * Preamble
  29.  *****************************************************************************/
  30. #include <stdio.h>                                               /* required */
  31. #include <stdarg.h>                                       /* va_list for BSD */
  32. #include <stdlib.h>                                              /* malloc() */
  33. #include <string.h>                                            /* strerror() */
  34.  
  35. #include <vlc/vlc.h>
  36.  
  37. #ifdef HAVE_FCNTL_H
  38. #   include <fcntl.h>                  /* O_CREAT, O_TRUNC, O_WRONLY, O_SYNC */
  39. #endif
  40.  
  41. #ifdef HAVE_ERRNO_H
  42. #   include <errno.h>                                               /* errno */
  43. #endif
  44.  
  45. #ifdef HAVE_UNISTD_H
  46. #include <unistd.h>                                      /* close(), write() */
  47. #endif
  48.  
  49. #include "interface.h"
  50.  
  51. /*****************************************************************************
  52.  * Local prototypes
  53.  *****************************************************************************/
  54. static void QueueMsg ( vlc_object_t *, int , const char *,
  55.                        const char *, va_list );
  56. static void FlushMsg ( msg_bank_t * );
  57. static void PrintMsg ( vlc_object_t *, msg_item_t * );
  58.  
  59. /*****************************************************************************
  60.  * msg_Create: initialize messages interface
  61.  *****************************************************************************
  62.  * This functions has to be called before any call to other msg_* functions.
  63.  * It set up the locks and the message queue if it is used.
  64.  *****************************************************************************/
  65. void __msg_Create( vlc_object_t *p_this )
  66. {
  67.     /* Message queue initialization */
  68.     vlc_mutex_init( p_this, &p_this->p_libvlc->msg_bank.lock );
  69.  
  70.     p_this->p_libvlc->msg_bank.b_configured = VLC_FALSE;
  71.     p_this->p_libvlc->msg_bank.b_overflow = VLC_FALSE;
  72.  
  73.     p_this->p_libvlc->msg_bank.i_start = 0;
  74.     p_this->p_libvlc->msg_bank.i_stop = 0;
  75.  
  76.     p_this->p_libvlc->msg_bank.i_sub = 0;
  77.     p_this->p_libvlc->msg_bank.pp_sub = NULL;
  78.  
  79. #ifdef UNDER_CE
  80.     p_this->p_libvlc->msg_bank.logfile =
  81.         CreateFile( L"vlc-log.txt", GENERIC_WRITE,
  82.                     FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
  83.                     CREATE_ALWAYS, 0, NULL );
  84.     SetFilePointer( p_this->p_libvlc->msg_bank.logfile, 0, NULL, FILE_END );
  85. #endif
  86. }
  87.  
  88. /*****************************************************************************
  89.  * msg_Flush: flush the message queue
  90.  *****************************************************************************/
  91. void __msg_Flush( vlc_object_t *p_this )
  92. {
  93.     int i_index;
  94.  
  95.     vlc_mutex_lock( &p_this->p_libvlc->msg_bank.lock );
  96.  
  97.     p_this->p_libvlc->msg_bank.b_configured = VLC_TRUE;
  98.  
  99.     for( i_index = p_this->p_libvlc->msg_bank.i_start;
  100.          i_index != p_this->p_libvlc->msg_bank.i_stop;
  101.          i_index = (i_index+1) % VLC_MSG_QSIZE )
  102.     {
  103.         PrintMsg( p_this, &p_this->p_libvlc->msg_bank.msg[i_index] );
  104.     }
  105.  
  106.     FlushMsg( &p_this->p_libvlc->msg_bank );
  107.  
  108.     vlc_mutex_unlock( &p_this->p_libvlc->msg_bank.lock );
  109. }
  110.  
  111. /*****************************************************************************
  112.  * msg_Destroy: free resources allocated by msg_Create
  113.  *****************************************************************************
  114.  * This functions prints all messages remaining in queue, then free all the
  115.  * resources allocated by msg_Create.
  116.  * No other messages interface functions should be called after this one.
  117.  *****************************************************************************/
  118. void __msg_Destroy( vlc_object_t *p_this )
  119. {
  120.     if( p_this->p_libvlc->msg_bank.i_sub )
  121.     {
  122.         msg_Err( p_this, "stale interface subscribers" );
  123.     }
  124.  
  125.     /* Flush the queue */
  126.     if( !p_this->p_libvlc->msg_bank.b_configured )
  127.     {
  128.         msg_Flush( p_this );
  129.     }
  130.     else
  131.     {
  132.         FlushMsg( &p_this->p_libvlc->msg_bank );
  133.     }
  134.  
  135. #ifdef UNDER_CE
  136.     CloseHandle( p_this->p_libvlc->msg_bank.logfile );
  137. #endif
  138.  
  139.     /* Destroy lock */
  140.     vlc_mutex_destroy( &p_this->p_libvlc->msg_bank.lock );
  141. }
  142.  
  143. /*****************************************************************************
  144.  * msg_Subscribe: subscribe to the message queue.
  145.  *****************************************************************************/
  146. msg_subscription_t *__msg_Subscribe( vlc_object_t *p_this )
  147. {
  148.     msg_bank_t *p_bank = &p_this->p_libvlc->msg_bank;
  149.     msg_subscription_t *p_sub = malloc( sizeof( msg_subscription_t ) );
  150.  
  151.     vlc_mutex_lock( &p_bank->lock );
  152.  
  153.     /* Add subscription to the list */
  154.     INSERT_ELEM( p_bank->pp_sub, p_bank->i_sub, p_bank->i_sub, p_sub );
  155.  
  156.     p_sub->i_start = p_bank->i_start;
  157.     p_sub->pi_stop = &p_bank->i_stop;
  158.  
  159.     p_sub->p_msg   = p_bank->msg;
  160.     p_sub->p_lock  = &p_bank->lock;
  161.  
  162.     vlc_mutex_unlock( &p_bank->lock );
  163.  
  164.     return p_sub;
  165. }
  166.  
  167. /*****************************************************************************
  168.  * msg_Unsubscribe: unsubscribe from the message queue.
  169.  *****************************************************************************/
  170. void __msg_Unsubscribe( vlc_object_t *p_this, msg_subscription_t *p_sub )
  171. {
  172.     msg_bank_t *p_bank = &p_this->p_libvlc->msg_bank;
  173.     int i_index;
  174.  
  175.     vlc_mutex_lock( &p_bank->lock );
  176.  
  177.     /* Sanity check */
  178.     if( !p_bank->i_sub )
  179.     {
  180.         msg_Err( p_this, "no subscriber in the list" );
  181.         return;
  182.     }
  183.  
  184.     /* Look for the appropriate subscription */
  185.     for( i_index = 0; i_index < p_bank->i_sub; i_index++ )
  186.     {
  187.         if( p_bank->pp_sub[ i_index ] == p_sub )
  188.         {
  189.             break;
  190.         }
  191.     }
  192.  
  193.     if( p_bank->pp_sub[ i_index ] != p_sub )
  194.     {
  195.         msg_Err( p_this, "subscriber not found" );
  196.         vlc_mutex_unlock( &p_bank->lock );
  197.         return;
  198.     }
  199.  
  200.     /* Remove this subscription */
  201.     REMOVE_ELEM( p_bank->pp_sub, p_bank->i_sub, i_index );
  202.  
  203.     vlc_mutex_unlock( &p_bank->lock );
  204. }
  205.  
  206. /*****************************************************************************
  207.  * __msg_*: print a message
  208.  *****************************************************************************
  209.  * These functions queue a message for later printing.
  210.  *****************************************************************************/
  211. void __msg_Generic( vlc_object_t *p_this, int i_type, const char *psz_module,
  212.                     const char *psz_format, ... )
  213. {
  214.     va_list args;
  215.  
  216.     va_start( args, psz_format );
  217.     QueueMsg( p_this, i_type, psz_module, psz_format, args );
  218.     va_end( args );
  219. }
  220.  
  221. /* Generic functions used when variadic macros are not available. */
  222. #define DECLARE_MSG_FN( FN_NAME, FN_TYPE ) \
  223.     void FN_NAME( void *p_this, const char *psz_format, ... ) \
  224.     { \
  225.         va_list args; \
  226.         va_start( args, psz_format ); \
  227.         QueueMsg( (vlc_object_t *)p_this, FN_TYPE, "unknown", \
  228.                   psz_format, args ); \
  229.         va_end( args ); \
  230.     } \
  231.     struct _
  232.  
  233. DECLARE_MSG_FN( __msg_Info, VLC_MSG_INFO );
  234. DECLARE_MSG_FN( __msg_Err,  VLC_MSG_ERR );
  235. DECLARE_MSG_FN( __msg_Warn, VLC_MSG_WARN );
  236. DECLARE_MSG_FN( __msg_Dbg,  VLC_MSG_DBG );
  237.  
  238. /*****************************************************************************
  239.  * QueueMsg: add a message to a queue
  240.  *****************************************************************************
  241.  * This function provides basic functionnalities to other msg_* functions.
  242.  * It adds a message to a queue (after having printed all stored messages if it
  243.  * is full). If the message can't be converted to string in memory, it issues
  244.  * a warning.
  245.  *****************************************************************************/
  246. static void QueueMsg( vlc_object_t *p_this, int i_type, const char *psz_module,
  247.                       const char *psz_format, va_list args )
  248. {
  249.     msg_bank_t * p_bank = &p_this->p_libvlc->msg_bank;       /* message bank */
  250.     char *       psz_str = NULL;                 /* formatted message string */
  251.     msg_item_t * p_item = NULL;                        /* pointer to message */
  252.     msg_item_t   item;                    /* message in case of a full queue */
  253.  
  254. #if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN)
  255.     int          i_size = strlen(psz_format) + INTF_MAX_MSG_SIZE;
  256. #endif
  257.  
  258.     /*
  259.      * Convert message to string
  260.      */
  261. #if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN)
  262.     vasprintf( &psz_str, psz_format, args );
  263. #else
  264.     psz_str = (char*) malloc( i_size * sizeof(char) );
  265. #endif
  266.  
  267.     if( psz_str == NULL )
  268.     {
  269. #ifdef HAVE_ERRNO_H
  270.         fprintf( stderr, "main warning: can't store message (%s): ",
  271.                  strerror(errno) );
  272. #else
  273.         fprintf( stderr, "main warning: can't store message: " );
  274. #endif
  275.         vfprintf( stderr, psz_format, args );
  276.         fprintf( stderr, "\n" );
  277.         return;
  278.     }
  279.  
  280. #if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN)
  281.     vsnprintf( psz_str, i_size, psz_format, args );
  282.     psz_str[ i_size - 1 ] = 0; /* Just in case */
  283. #endif
  284.  
  285.     /* Put message in queue */
  286.     vlc_mutex_lock( &p_bank->lock );
  287.  
  288.     /* Check there is room in the queue for our message */
  289.     if( p_bank->b_overflow )
  290.     {
  291.         FlushMsg( p_bank );
  292.  
  293.         if( ((p_bank->i_stop - p_bank->i_start + 1) % VLC_MSG_QSIZE) == 0 )
  294.         {
  295.             /* Still in overflow mode, print from a dummy item */
  296.             p_item = &item;
  297.         }
  298.         else
  299.         {
  300.             /* Pheeew, at last, there is room in the queue! */
  301.             p_bank->b_overflow = VLC_FALSE;
  302.         }
  303.     }
  304.     else if( ((p_bank->i_stop - p_bank->i_start + 2) % VLC_MSG_QSIZE) == 0 )
  305.     {
  306.         FlushMsg( p_bank );
  307.  
  308.         if( ((p_bank->i_stop - p_bank->i_start + 2) % VLC_MSG_QSIZE) == 0 )
  309.         {
  310.             p_bank->b_overflow = VLC_TRUE;
  311.  
  312.             /* Put the overflow message in the queue */
  313.             p_item = p_bank->msg + p_bank->i_stop;
  314.             p_bank->i_stop = (p_bank->i_stop + 1) % VLC_MSG_QSIZE;
  315.  
  316.             p_item->i_type =        VLC_MSG_WARN;
  317.             p_item->i_object_id =   p_this->i_object_id;
  318.             p_item->i_object_type = p_this->i_object_type;
  319.             p_item->psz_module =    strdup( "message" );
  320.             p_item->psz_msg =       strdup( "message queue overflowed" );
  321.  
  322.             PrintMsg( p_this, p_item );
  323.  
  324.             /* We print from a dummy item */
  325.             p_item = &item;
  326.         }
  327.     }
  328.  
  329.     if( !p_bank->b_overflow )
  330.     {
  331.         /* Put the message in the queue */
  332.         p_item = p_bank->msg + p_bank->i_stop;
  333.         p_bank->i_stop = (p_bank->i_stop + 1) % VLC_MSG_QSIZE;
  334.     }
  335.  
  336.     /* Fill message information fields */
  337.     p_item->i_type =        i_type;
  338.     p_item->i_object_id =   p_this->i_object_id;
  339.     p_item->i_object_type = p_this->i_object_type;
  340.     p_item->psz_module =    strdup( psz_module );
  341.     p_item->psz_msg =       psz_str;
  342.  
  343.     PrintMsg( p_this, p_item );
  344.  
  345.     if( p_bank->b_overflow )
  346.     {
  347.         free( p_item->psz_module );
  348.         free( p_item->psz_msg );
  349.     }
  350.  
  351.     vlc_mutex_unlock( &p_bank->lock );
  352. }
  353.  
  354. /* following functions are local */
  355.  
  356. /*****************************************************************************
  357.  * FlushMsg
  358.  *****************************************************************************
  359.  * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
  360.  * this function does not check the lock.
  361.  *****************************************************************************/
  362. static void FlushMsg ( msg_bank_t *p_bank )
  363. {
  364.     int i_index, i_start, i_stop;
  365.  
  366.     /* Only flush the queue if it has been properly configured */
  367.     if( !p_bank->b_configured )
  368.     {
  369.         return;
  370.     }
  371.  
  372.     /* Get the maximum message index that can be freed */
  373.     i_stop = p_bank->i_stop;
  374.  
  375.     /* Check until which value we can free messages */
  376.     for( i_index = 0; i_index < p_bank->i_sub; i_index++ )
  377.     {
  378.         i_start = p_bank->pp_sub[ i_index ]->i_start;
  379.  
  380.         /* If this subscriber is late, we don't free messages before
  381.          * his i_start value, otherwise he'll miss messages */
  382.         if(   ( i_start < i_stop
  383.                && (p_bank->i_stop <= i_start || i_stop <= p_bank->i_stop) )
  384.            || ( i_stop < i_start
  385.                && (i_stop <= p_bank->i_stop && p_bank->i_stop <= i_start) ) )
  386.         {
  387.             i_stop = i_start;
  388.         }
  389.     }
  390.  
  391.     /* Free message data */
  392.     for( i_index = p_bank->i_start;
  393.          i_index != i_stop;
  394.          i_index = (i_index+1) % VLC_MSG_QSIZE )
  395.     {
  396.         free( p_bank->msg[i_index].psz_msg );
  397.         free( p_bank->msg[i_index].psz_module );
  398.     }
  399.  
  400.     /* Update the new start value */
  401.     p_bank->i_start = i_index;
  402. }
  403.  
  404. /*****************************************************************************
  405.  * PrintMsg: output a message item to stderr
  406.  *****************************************************************************
  407.  * Print a message to stderr, with colour formatting if needed.
  408.  *****************************************************************************/
  409. static void PrintMsg ( vlc_object_t * p_this, msg_item_t * p_item )
  410. {
  411. #ifndef WIN32
  412. #   define COL(x)  "\033[" #x ";1m"
  413. #   define RED     COL(31)
  414. #   define GREEN   COL(32)
  415. #   define YELLOW  COL(33)
  416. #   define WHITE   COL(37)
  417. #   define GRAY    "\033[0m"
  418. #else
  419. #   define RED     ""
  420. #   define GREEN   ""
  421. #   define YELLOW  ""
  422. #   define WHITE   ""
  423. #   define GRAY    ""
  424. #endif
  425.  
  426. #ifdef UNDER_CE
  427.     int i_dummy;
  428. #endif
  429.     static const char * ppsz_type[4] = { "", " error", " warning", " debug" };
  430.     static const char *ppsz_color[4] = { WHITE, RED, YELLOW, GRAY };
  431.     char *psz_object = "private";
  432.     int i_type = p_item->i_type;
  433.  
  434.     switch( i_type )
  435.     {
  436.         case VLC_MSG_ERR:
  437.             if( p_this->p_libvlc->i_verbose < 0 ) return;
  438.             break;
  439.         case VLC_MSG_INFO:
  440.             if( p_this->p_libvlc->i_verbose < 0 ) return;
  441.             break;
  442.         case VLC_MSG_WARN:
  443.             if( p_this->p_libvlc->i_verbose < 1 ) return;
  444.             break;
  445.         case VLC_MSG_DBG:
  446.             if( p_this->p_libvlc->i_verbose < 2 ) return;
  447.             break;
  448.     }
  449.  
  450.     switch( p_item->i_object_type )
  451.     {
  452.         case VLC_OBJECT_ROOT: psz_object = "root"; break;
  453.         case VLC_OBJECT_VLC: psz_object = "vlc"; break;
  454.         case VLC_OBJECT_MODULE: psz_object = "module"; break;
  455.         case VLC_OBJECT_INTF: psz_object = "interface"; break;
  456.         case VLC_OBJECT_PLAYLIST: psz_object = "playlist"; break;
  457.         case VLC_OBJECT_ITEM: psz_object = "item"; break;
  458.         case VLC_OBJECT_INPUT: psz_object = "input"; break;
  459.         case VLC_OBJECT_DECODER: psz_object = "decoder"; break;
  460.         case VLC_OBJECT_VOUT: psz_object = "video output"; break;
  461.         case VLC_OBJECT_AOUT: psz_object = "audio output"; break;
  462.         case VLC_OBJECT_SOUT: psz_object = "stream output"; break;
  463.     }
  464.  
  465. #ifdef UNDER_CE
  466. #   define CE_WRITE(str) WriteFile( p_this->p_libvlc->msg_bank.logfile, \
  467.                                     str, strlen(str), &i_dummy, NULL );
  468.     CE_WRITE( p_item->psz_module );
  469.     CE_WRITE( " " );
  470.     CE_WRITE( psz_object );
  471.     CE_WRITE( ppsz_type[i_type] );
  472.     CE_WRITE( ": " );
  473.     CE_WRITE( p_item->psz_msg );
  474.     CE_WRITE( "\r\n" );
  475.     FlushFileBuffers( p_this->p_libvlc->msg_bank.logfile );
  476.  
  477. #else
  478.     /* Send the message to stderr */
  479.     if( p_this->p_libvlc->b_color )
  480.     {
  481.         fprintf( stderr, "[" GREEN "%.8i" GRAY "] %s %s%s: %s%s" GRAY "\n",
  482.                          p_item->i_object_id, p_item->psz_module, psz_object,
  483.                          ppsz_type[i_type], ppsz_color[i_type],
  484.                          p_item->psz_msg );
  485.     }
  486.     else
  487.     {
  488.         fprintf( stderr, "[%.8i] %s %s%s: %s\n", p_item->i_object_id,
  489.                          p_item->psz_module, psz_object, ppsz_type[i_type],
  490.                          p_item->psz_msg );
  491.     }
  492.  
  493. #   if defined(WIN32)
  494.     fflush( stderr );
  495. #   endif
  496. #endif
  497. }
  498.